﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Xna.Framework;
using System.Threading;

namespace PowerLife
{
    //World contains the information on the gameworld, including chunk count, worldfile, etc
    //
    class World
    {
        public int xChunks { get; set;} //number of chunks in x axis
        public int yChunks { get; set;} //number of chunks in y axis
        public int ChunkSize { get; set;} //number of nodes in one chunk axis

        public int seed{ get; set;} //world generation seed.
        public string worldName{ get; set;}
        public Chunk[,] chunkArray;

  
        
        



        public World(int xChunks, int yChunks, int ChunkSize, int seed, string worldName, float camX, float camY)
        {
            this.xChunks = xChunks;
            this.yChunks = yChunks;

            //N number of nodes in one axis of a chunk
            this.ChunkSize = ChunkSize;
            //seed for world generation (not yet implemented)
            this.seed = seed;
            //filename for world (not yet implemented)
            this.worldName = worldName;

            //4x4 grid of chunks loaded in memory at any one time
            chunkArray = new Chunk[4, 4];

            //initial world load at camera
            for (int x = 0; x < 4; x++)
            {
                for (int y = 0; y < 4; y++)
                {
                    //loads chunk into the matrix, offset by the location of the camera (loads chunks around location of starting position of camera)
                    chunkArray[x, y] = new Chunk(ChunkSize, x * ChunkSize + (int)(camX / ChunkSize) * ChunkSize - 2 * ChunkSize, y * ChunkSize + (int)(camY / ChunkSize) * ChunkSize - 2 * ChunkSize, ChunkSize * xChunks, ChunkSize * yChunks);
                    //check if a chunk would be outside of world
                    if (chunkArray[x, y].Xloc < 0 || chunkArray[x, y].Xloc > xChunks * ChunkSize
                        || chunkArray[x, y].Yloc < 0 || chunkArray[x, y].Yloc > yChunks * ChunkSize)
                    {
                        System.Diagnostics.Debug.WriteLine("Loading out of bounds chunk. TODO: Determine how to handle null chunks");
                        chunkArray[x, y].loadChunk(worldName);
                    }

                    else
                    {
                        chunkArray[x, y].loadChunk(worldName);
                        System.Diagnostics.Debug.WriteLine("Loading chunk at :" + chunkArray[x, y].Xloc + "  " + chunkArray[x, y].Yloc);
                    }
                    
                }
            }
        }


        public void loadWorld(String worldName)
        {
            //load width and height
            //load chunksize
            string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            using (StreamReader sr = new StreamReader(mydocpath + "\\" + worldName + ".world"))
            {
                xChunks = Convert.ToInt32(sr.ReadLine());
                yChunks = Convert.ToInt32(sr.ReadLine());
                ChunkSize = Convert.ToInt32(sr.ReadLine());
            }
        }

        //main method for updating world info. Currently only updates which chunks are loaded.
        public void updateWorld(ViewPort currView)
        {

            shiftChunkMatrix(currView);

        }

        //shiftChunkmatrix is a cumbersome method that shifts the values in the 'loaded chunk matrix' in a certain direction, based on the camera location. Unloads the side pushed out and loads the side pushed in.
        private void shiftChunkMatrix(ViewPort currView)
        {
            float viewLocX = currView.xloc;
            float viewLocY = currView.yloc;

            if (viewLocY - chunkArray[0, 0].Yloc > 3 * ChunkSize)
            {
                System.Diagnostics.Debug.WriteLine("top row shifting");
                System.Diagnostics.Debug.WriteLine("Previous bottom row y val: " + chunkArray[0, 3].Yloc);

                int prevXloc = chunkArray[0, 3].Xloc;
                int prevYloc = chunkArray[0, 3].Yloc;

                chunkArray[0, 0].freeChunk();
                chunkArray[1, 0].freeChunk();
                chunkArray[2, 0].freeChunk();
                chunkArray[3, 0].freeChunk();

                chunkArray[0, 0] = chunkArray[0, 1];
                chunkArray[1, 0] = chunkArray[1, 1];
                chunkArray[2, 0] = chunkArray[2, 1];
                chunkArray[3, 0] = chunkArray[3, 1];

                chunkArray[0, 1] = chunkArray[0, 2];
                chunkArray[1, 1] = chunkArray[1, 2];
                chunkArray[2, 1] = chunkArray[2, 2];
                chunkArray[3, 1] = chunkArray[3, 2];

                chunkArray[0, 2] = chunkArray[0, 3];
                chunkArray[1, 2] = chunkArray[1, 3];
                chunkArray[2, 2] = chunkArray[2, 3];
                chunkArray[3, 2] = chunkArray[3, 3];

                chunkArray[0, 3] = new Chunk(ChunkSize, prevXloc, prevYloc + ChunkSize, ChunkSize*xChunks, ChunkSize*yChunks);
                chunkArray[1, 3] = new Chunk(ChunkSize, prevXloc + ChunkSize, prevYloc + ChunkSize, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[2, 3] = new Chunk(ChunkSize, prevXloc + 2 * ChunkSize, prevYloc + ChunkSize, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[3, 3] = new Chunk(ChunkSize, prevXloc + 3 * ChunkSize, prevYloc + ChunkSize, ChunkSize * xChunks, ChunkSize * yChunks);
                System.Diagnostics.Debug.WriteLine("New bottom row y val: " + chunkArray[0, 3].Yloc);
                System.Diagnostics.Debug.WriteLine("New top row y val: " + chunkArray[0, 0].Yloc);
                ThreadStart ts0 = delegate { chunkArray[0, 3].loadChunk(worldName); };
                Thread newThread0 = new Thread(ts0);
                ThreadStart ts1 = delegate { chunkArray[1, 3].loadChunk(worldName); };
                Thread newThread1 = new Thread(ts1);
                ThreadStart ts2 = delegate { chunkArray[2, 3].loadChunk(worldName); };
                Thread newThread2 = new Thread(ts2);
                ThreadStart ts3 = delegate { chunkArray[3, 3].loadChunk(worldName); };
                Thread newThread3 = new Thread(ts3);

                newThread0.Start();
                newThread1.Start();
                newThread2.Start();
                newThread3.Start();
            }
            //if chunk on bottom row is more than three chunk-heights from bottom of camera, shift matrix;
            if ((viewLocY ) - chunkArray[0, 3].Yloc < -2.0 * ChunkSize)
            {
                System.Diagnostics.Debug.WriteLine("bot row shifting");

                int prevXloc = chunkArray[0, 0].Xloc;
                int prevYloc = chunkArray[0, 0].Yloc;

                chunkArray[0, 3].freeChunk();
                chunkArray[1, 3].freeChunk();
                chunkArray[2, 3].freeChunk();
                chunkArray[3, 3].freeChunk();

                chunkArray[0, 3] = chunkArray[0, 2];
                chunkArray[1, 3] = chunkArray[1, 2];
                chunkArray[2, 3] = chunkArray[2, 2];
                chunkArray[3, 3] = chunkArray[3, 2];

                chunkArray[0, 2] = chunkArray[0, 1];
                chunkArray[1, 2] = chunkArray[1, 1];
                chunkArray[2, 2] = chunkArray[2, 1];
                chunkArray[3, 2] = chunkArray[3, 1];

                chunkArray[0, 1] = chunkArray[0, 0];
                chunkArray[1, 1] = chunkArray[1, 0];
                chunkArray[2, 1] = chunkArray[2, 0];
                chunkArray[3, 1] = chunkArray[3, 0];

                chunkArray[0, 0] = new Chunk(ChunkSize, prevXloc, prevYloc - ChunkSize, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[1, 0] = new Chunk(ChunkSize, prevXloc + ChunkSize, prevYloc - ChunkSize, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[2, 0] = new Chunk(ChunkSize, prevXloc + 2 * ChunkSize, prevYloc - ChunkSize, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[3, 0] = new Chunk(ChunkSize, prevXloc + 3 * ChunkSize, prevYloc - ChunkSize, ChunkSize * xChunks, ChunkSize * yChunks);
                System.Diagnostics.Debug.WriteLine("New bottom row y val: " + chunkArray[0, 0].Yloc);
                ThreadStart ts0 = delegate { chunkArray[0, 0].loadChunk(worldName); };
                Thread newThread0 = new Thread(ts0);
                ThreadStart ts1 = delegate { chunkArray[1, 0].loadChunk(worldName); };
                Thread newThread1 = new Thread(ts1);
                ThreadStart ts2 = delegate { chunkArray[2, 0].loadChunk(worldName); };
                Thread newThread2 = new Thread(ts2);
                ThreadStart ts3 = delegate { chunkArray[3, 0].loadChunk(worldName); };
                Thread newThread3 = new Thread(ts3);

                newThread0.Start();
                newThread1.Start();
                newThread2.Start();
                newThread3.Start();
            }
            //if chunk on left row is more than three chunk-widths from left of camera, shift matrix
            if (viewLocX - chunkArray[0, 0].Xloc > 3 * ChunkSize)
            {
                System.Diagnostics.Debug.WriteLine("left col shifting");

                int prevXloc = chunkArray[3, 0].Xloc;
                int prevYloc = chunkArray[3, 0].Yloc;

                chunkArray[0, 0].freeChunk();
                chunkArray[0, 1].freeChunk();
                chunkArray[0, 2].freeChunk();
                chunkArray[0, 3].freeChunk();

                chunkArray[0, 0] = chunkArray[1, 0];
                chunkArray[0, 1] = chunkArray[1, 1];
                chunkArray[0, 2] = chunkArray[1, 2];
                chunkArray[0, 3] = chunkArray[1, 3];

                chunkArray[1, 0] = chunkArray[2, 0];
                chunkArray[1, 1] = chunkArray[2, 1];
                chunkArray[1, 2] = chunkArray[2, 2];
                chunkArray[1, 3] = chunkArray[2, 3];

                chunkArray[2, 0] = chunkArray[3, 0];
                chunkArray[2, 1] = chunkArray[3, 1];
                chunkArray[2, 2] = chunkArray[3, 2];
                chunkArray[2, 3] = chunkArray[3, 3];

                chunkArray[3, 0] = new Chunk(ChunkSize, prevXloc + ChunkSize, prevYloc, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[3, 1] = new Chunk(ChunkSize, prevXloc + ChunkSize, prevYloc + ChunkSize * 1, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[3, 2] = new Chunk(ChunkSize, prevXloc + ChunkSize, prevYloc + ChunkSize * 2, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[3, 3] = new Chunk(ChunkSize, prevXloc + ChunkSize, prevYloc + ChunkSize * 3, ChunkSize * xChunks, ChunkSize * yChunks);
                System.Diagnostics.Debug.WriteLine("New right column x val: " + chunkArray[3, 0].Xloc);
                System.Diagnostics.Debug.WriteLine("New left column x val: " + chunkArray[0, 0].Xloc);

                ThreadStart ts0 = delegate { chunkArray[3, 0].loadChunk(worldName); };
                Thread newThread0 = new Thread(ts0);
                ThreadStart ts1 = delegate { chunkArray[3, 1].loadChunk(worldName); };
                Thread newThread1 = new Thread(ts1);
                ThreadStart ts2 = delegate { chunkArray[3, 2].loadChunk(worldName); };
                Thread newThread2 = new Thread(ts2);
                ThreadStart ts3 = delegate { chunkArray[3, 3].loadChunk(worldName); };
                Thread newThread3 = new Thread(ts3);
                newThread0.Start();
                newThread1.Start();
                newThread2.Start();
                newThread3.Start();
            }

            //if chunk on right row is more than three chunk-widths from right of camera, shift matrix;


            if ( (chunkArray[3,0].Xloc + ChunkSize) - (currView.xloc) > 3*ChunkSize)
            {

                System.Diagnostics.Debug.WriteLine("right col shifting out");

                int prevXloc = chunkArray[0, 0].Xloc;
                int prevYloc = chunkArray[0, 0].Yloc;

                chunkArray[3, 0].freeChunk();
                chunkArray[3, 1].freeChunk();
                chunkArray[3, 2].freeChunk();
                chunkArray[3, 3].freeChunk();

                chunkArray[3, 0] = chunkArray[2, 0];
                chunkArray[3, 1] = chunkArray[2, 1];
                chunkArray[3, 2] = chunkArray[2, 2];
                chunkArray[3, 3] = chunkArray[2, 3];

                chunkArray[2, 0] = chunkArray[1, 0];
                chunkArray[2, 1] = chunkArray[1, 1];
                chunkArray[2, 2] = chunkArray[1, 2];
                chunkArray[2, 3] = chunkArray[1, 3];

                chunkArray[1, 0] = chunkArray[0, 0];
                chunkArray[1, 1] = chunkArray[0, 1];
                chunkArray[1, 2] = chunkArray[0, 2];
                chunkArray[1, 3] = chunkArray[0, 3];

                chunkArray[0, 0] = new Chunk(ChunkSize, prevXloc - ChunkSize, prevYloc, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[0, 1] = new Chunk(ChunkSize, prevXloc - ChunkSize, prevYloc + ChunkSize * 1, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[0, 2] = new Chunk(ChunkSize, prevXloc - ChunkSize, prevYloc + ChunkSize * 2, ChunkSize * xChunks, ChunkSize * yChunks);
                chunkArray[0, 3] = new Chunk(ChunkSize, prevXloc - ChunkSize, prevYloc + ChunkSize * 3, ChunkSize * xChunks, ChunkSize * yChunks);
                System.Diagnostics.Debug.WriteLine("New left column x val: " + chunkArray[0, 0].Xloc);
                ThreadStart ts0 = delegate { chunkArray[0, 0].loadChunk(worldName); };
                Thread newThread0 = new Thread(ts0);
                ThreadStart ts1 = delegate { chunkArray[0, 1].loadChunk(worldName); };
                Thread newThread1 = new Thread(ts1);
                ThreadStart ts2 = delegate { chunkArray[0, 2].loadChunk(worldName); };
                Thread newThread2 = new Thread(ts2);
                ThreadStart ts3 = delegate { chunkArray[0, 3].loadChunk(worldName); };
                Thread newThread3 = new Thread(ts3);
                newThread0.Start();
                newThread1.Start();
                newThread2.Start();
                newThread3.Start();
            }
        }


    }


}
